/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ajustecurvas.utils;

import ajustecurvas.Ponto;
import java.util.List;

/**
 *
 * @author Luan
 */
public class MinimosQuadrados {
    
    
    
    /*----------------------------------------------------------------
    Programa MinQuad
    calcula a funcao que melhor se ajusta aos pontos dados
    atraves do metodo dos minimos quadrados
    ----------------------------------------------------------------*/


    /* M estabelece quantos termos tem a funcao aproximadora */
    private int M ;
    
    private int N;
    private double[] X;
    private double[] Y;
    private double[][] A;
    private double[] B;
    


    private double funcao(int i,int k){
    /* o numero de termos da funcao aproximadora
    afeta as proximas linhas (switch) */
        
        if(i == 0)
            return 1;
        else{
            /* funcoes que compoem a funcao aproximadora */
            return Math.pow(X[k], i);
        }
    }

    private void SistemaNormal(){
        
        int i,j,k;
        double r,s;

        for (i=0; i<M; i++){
            for (j=0; j<M; j++)
                A[i][j]=0;
            B[i] = 0;
        }
        for (k=0; k<N; k++){
            for (i=0; i<M; i++){
                r = funcao(i,k);
                B[i] += r*Y[k];
                for (j=0; j<M; j++){
                    s = funcao(j,k);
                    A[i][j] += r*s;
                }
            }
        }
    }

    /* calculo do determinante de uma matriz 2x2 */
    private double det(double a,double b,double c,double d){
        return (a*d)-(b*c);
    }

    /* esta void mostra na tela o estado atual do sistema normal */
    private void Show(){
        int i,j;

        System.out.println("Ordem do sistema: n= " + N);
        System.out.println("");
        for ( i=0;i<M;i++ ){
            for ( j=0;j<M;j++ )
                System.out.print("  " + A[i][j]);
            System.out.println("  " + B[i]);
        }
    }


    /* faz a triangularizacao do sistema pelo metodo de Gauss */
    private void TriGauss(){
        int i,j,k;

    //    Show();
        for (k=0; k<(M-1); k++){
            for ( i=k+1; i<M; i++ ){
                for ( j=k+1; j<M; j++ )
                    A[i][j]=det(A[k][k],A[i][k],A[k][j],A[i][j]);
                B[i]=det(A[k][k],A[i][k],B[k],B[i]);
                A[i][k] = 0;
              //  Show();
            }
        }
    }

    /* calcula a matriz das solucoes do sistema ja triangularizado */
    private void SolGauss(){
        int k,j;
        double s;

        X[M-1]=B[M-1]/A[M-1][M-1];
        for ( k=M-2; k>=0; k-- ){
            s=0;
            for ( j=k+1; j<M; j++)
            s+=A[k][j]*X[j];
            X[k]=(B[k]-s)/A[k][k];
        }
    }


        /* mostra o resultado da matriz de solucoes */
    private void Imprime(){
        int i;

        System.out.println("");
        System.out.println("Solucao do sistema linear");
        System.out.println("");
        for ( i=0;i<M;i++ )
            System.out.println("a(" + i + ") = " + X[i]);
        System.out.println("Problema encerrado.");
    }

    /* programa principal */
    public double[] run(List<Ponto> pontos, int termos){
        
        X = new double[pontos.size()];
        Y = new double[pontos.size()];
        A = new double [pontos.size()][pontos.size()];
        B = new double[pontos.size()];
        N = pontos.size();
        M = termos;
        
    //    System.out.println(N);
        
        for(int i = 0; i<pontos.size(); i++){
            X[i] = pontos.get(i).getX();
            Y[i] = pontos.get(i).getY();
        }
        
        SistemaNormal();
        TriGauss();
      //  Show();
        SolGauss();
      //  Imprime();

        return X;
    }


    
}
